//! 这个文件夹下面定义自己的路由API，
//! 这个框架中的路由函数参数的拾取器都没有被使用， 因为有跨越的存在，
//! 我们需要从Request<Body>中获取到Origin字段，以便Response中返回，
//! 这样浏览器才会接收.
//!

mod define;

use crate::{
    error,
    middleware::{FilterWhiteListLayer, OptionRequestLayer, ResponseWithOriginLayer},
    CONFIG,
};
use axum::{
    error_handling::HandleErrorLayer, http::StatusCode, response::IntoResponse, BoxError, Router,
};
use sea_orm::DatabaseConnection;
use tower::ServiceBuilder;
use tower_http::{add_extension::AddExtensionLayer, trace::TraceLayer};

/// 总的创建路由函数
pub async fn router_new(db_connection: DatabaseConnection) -> Router {
    let config = CONFIG.get().unwrap();
    let white_list = &config.server.cross_domain_white_list;
    Router::new()
        .merge(define::define_routers())
        .layer(
            ServiceBuilder::new()
                .layer(HandleErrorLayer::new(handle_error))
                .timeout(std::time::Duration::from_secs(30))
                .layer(TraceLayer::new_for_http())
                .layer(AddExtensionLayer::new(db_connection))
                .layer(FilterWhiteListLayer::new(white_list.clone()))
                .layer(ResponseWithOriginLayer::new())
                .layer(OptionRequestLayer::new()),
        )
        .fallback(not_found)
}

// 没有找到API的错误处理
async fn not_found() -> (StatusCode, &'static str) {
    (StatusCode::NOT_FOUND, "your request api does not exists")
}

// 顶层的错误处理
pub async fn handle_error(error: BoxError) -> impl IntoResponse {
    tracing::error!("{}", error);
    if error.is::<tower::timeout::error::Elapsed>() {
        (StatusCode::REQUEST_TIMEOUT, "请求超时".to_string()).into_response()
    } else if error.is::<crate::middleware::MiddleError>() {
        let err = *error.downcast::<crate::middleware::MiddleError>().unwrap();
        error::Error::from((err.0, err.1.as_str())).into_response()
    } else {
        (
            StatusCode::INTERNAL_SERVER_ERROR,
            "服务器内部未知错误".to_string(),
        )
            .into_response()
    }
}
